package xyz.penghaonan.wificonnect.connect;

import android.net.ConnectivityManager;
import android.net.wifi.WifiInfo;

import com.penghaonan.appframework.utils.Logger;
import com.penghaonan.appframework.utils.NetworkUtils;
import com.penghaonan.appframework.utils.monitor.IMonitor;
import com.penghaonan.appframework.utils.monitor.MonitorManager;

import xyz.penghaonan.wificonnect.WifiConnectSDK;
import xyz.penghaonan.wificonnect.message.BaseResponseMsg;
import xyz.penghaonan.wificonnect.message.IResponseListener;
import xyz.penghaonan.wificonnect.message.KeepAliveRequestMsg;
import xyz.penghaonan.wificonnect.message.KeepAliveResponseMsg;
import xyz.penghaonan.wificonnect.message.LocationInfoRequestMsg;
import xyz.penghaonan.wificonnect.message.MsgSender;
import xyz.penghaonan.wificonnect.sockethelper.BaseSocketHelper;
import xyz.penghaonan.wificonnect.sockethelper.ServerSocketHelper;

public class DeviceConnectHelper extends BaseConnectHelper {

    protected ServerSocketHelper socketHelper;
    private WifiInfo wifiInfo;
    private final KeepAliveHelper keepAliveHelper = new KeepAliveHelper();
    private final ServerSocketHelper.DeviceConnectListener connectListener = new ServerSocketHelper.DeviceConnectListener() {
        @Override
        public void onDeviceConnectStateChanged(int state) {
            switch (state) {
                case BaseSocketHelper.DeviceConnectListener
                        .STATE_CONNECTED:
                    setState(STATE_SOCKET_CONNECTED);
                    keepAliveHelper.onSocketConnected();
                    break;
                case BaseSocketHelper.DeviceConnectListener
                        .STATE_DISCONNECT:
                    keepAliveHelper.onSocketDisConnect();
                    setState(STATE_OFF);
                    break;
                case BaseSocketHelper.DeviceConnectListener
                        .STATE_WAITING:
                    keepAliveHelper.onSocketDisConnect();
                    setState(STATE_WAITING);
                    break;
            }
        }
    };
    private final IMonitor.MonitorListener<Boolean> networkMonitor = new IMonitor.MonitorListener<Boolean>() {
        @Override
        public void onStatusChanged(IMonitor<Boolean> monitor, Boolean value) {
            checkNetwork();
        }
    };

    @Override
    public void start() {
        MonitorManager.getNetworkMonitor().addListener(networkMonitor);
        checkNetwork();
    }

    private void checkNetwork() {
        if (NetworkUtils.getNetype() == ConnectivityManager.TYPE_WIFI) {
            if (!isWifiConnectedState()) {
                setState(STATE_WIFI_CONNECTED);
                createSocket();
            } else if (socketHelper == null) {
                createSocket();
            }
        } else {
            releaseSocket();
            setState(STATE_WIFI_LISTENING);
        }
    }

    @Override
    public void stop() {
        MonitorManager.getNetworkMonitor().removeListener(networkMonitor);
        releaseSocket();
    }

    private void releaseSocket() {
        if (socketHelper != null) {
            socketHelper.release();
            socketHelper = null;
        }
    }

    @Override
    public BaseSocketHelper getSocketHelper() {
        return socketHelper;
    }

    public WifiInfo getWifiInfo() {
        return wifiInfo;
    }

    public String getIpAddress() {
        if (wifiInfo == null || wifiInfo.getIpAddress() == 0) {
            return "";
        }
        int ipAddress = wifiInfo.getIpAddress();
        return (ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff) + "." + (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff);
    }

    private void createSocket() {
        wifiInfo = WifiConnectSDK.getWifiManager().getConnectionInfo();
        if (wifiInfo == null) {
            return;
        }
        setState(STATE_SOCKET_CREATE);
        socketHelper = new ServerSocketHelper();
        socketHelper.addDeviceConnectListener(connectListener);
        setState(STATE_SOCKET_WAITING);
    }

    private class KeepAliveHelper {
        private boolean hasPostDisconnectTask;
        private LocationInfoRequestMsg locationInfoRequestMsg;
        private final Runnable keepAliveTask = new Runnable() {
            @Override
            public void run() {
                if (!hasPostDisconnectTask) {
                    handler.postDelayed(disconnectTask, TIME_OUT);
                    Logger.i("post disconnectTask");
                    hasPostDisconnectTask = true;
                }

                handler.removeCallbacks(keepAliveTask);
                handler.postDelayed(keepAliveTask, 2000);
                if (locationInfoRequestMsg == null) {
                    locationInfoRequestMsg = new LocationInfoRequestMsg();
                    locationInfoRequestMsg.setOnOff(true);
                    MsgSender.sendMsg(locationInfoRequestMsg);
                }

                MsgSender.sendMsg(new KeepAliveRequestMsg(), new IResponseListener() {
                    @Override
                    public void onResponse(BaseResponseMsg msg) {
                        if (msg instanceof KeepAliveResponseMsg) {
                            handler.removeCallbacks(disconnectTask);
                            Logger.i("remove disconnectTask");
                            hasPostDisconnectTask = false;
                        }
                    }
                });
            }
        };
        private final Runnable disconnectTask = new Runnable() {
            @Override
            public void run() {
                Logger.i("do disconnectTask");
                locationInfoRequestMsg = null;
                handler.removeCallbacks(keepAliveTask);
                releaseSocket();
                checkNetwork();
            }
        };

        void onSocketConnected() {
            handler.removeCallbacks(disconnectTask);
            handler.removeCallbacks(keepAliveTask);
            handler.post(keepAliveTask);
        }

        void onSocketDisConnect() {
            locationInfoRequestMsg = null;
            handler.removeCallbacks(disconnectTask);
            handler.removeCallbacks(keepAliveTask);
        }
    }
}
